/**
 * @file            文件名:                WinyunqKeyboard.c
 * @brief           函数简介
 *  @details        【不能简单描述则必选】如果不能一句话描述函数，请使用Details进行详细描述
 *
 * @author          Winyunq             创建
 * @version         版本:                 1.0.0
 * @date            2022-12-16          创建
 *
 * Copyright (c) 2022  Winyunq科技公司
 */
#define __WinyunqKeyboard_C
#include "WinyunqKeyboard.h"
#include "WinyunqConfigure.h"
#include "CONFIG.h"
#include "devinfoservice.h"
#include "battservice.h"
#include "hidkbdservice.h"
#include "hiddev.h"
#include "hidkbd.h"

#if (PresskeyGroup == 'A')
#define IsTouch() GPIOA_ReadITFlagBit(Presskey)
#define WaitNewKey() GPIOA_ClearITFlagBit(-1);
#define isReleaseKey() GPIOA_ReadPortPin(Presskey)
#elif (PresskeyGroup == 'B')
#define IsTouch() GPIOB_ReadITFlagBit(Presskey)
#define WaitNewKey() GPIOB_ClearITFlagBit(-1);
#define isReleaseKey() GPIOB_ReadPortPin(Presskey)
#endif
uint8 NowReportTime = 0;
char test[19] = "Winyunq\0";
void (*ReportKeyValue)();
char ReportChar[256] = {"48125  "};
/**
 * @brief           当前按键运行状态变量
 *  @details
 * | 值 | 含义 | 按键状态 | 成因 |
 * | ---- | ---- | ---- | ---- |
 * | 0 | 按键上报操作已经结束 | 除按键按下这个动作以外的任意状态 | 只有当ReportKeyValue需要的按键操作均已经结束时，ReportKeyValue函数将NowReportTime置零表示不再需要执行ReportKeyValue函数 |
 * | 1 | 此刻按键被按下。从按键松开的情况下再度按下 | 从松开到按下 | 按键松开，方有按下这个动作，方可产生下降沿动作。此时将执行NowReportTime置1，并立刻调用一次ReportKeyValue |
 * | 其它 | 按键运行中计数。有效时间从1开始 | 除按键按下这个动作以外的任意状态 | 为了将按键上报拆分成多个按键连续按下松开的操作，同时为了使得每个按键有按下一段时间，因此需要将ReportKeyValue拆成时变系统。NowReportTime即记录当前运行的时间 |
 *
 * */
/*
 * 创建者:             Winyunq
 * 创建日期:            2022-12-18
 *
 *      《初始化》
 * 修订内容:            创建函数
 * @author          Winyunq进行完善
 * @date            2022-12-18
 * @version         1.0.0
 */
void InitKeyboard()
{
    tmos_memcpy(KeyboardConfigure.details.ReportKey, test, 19);
    KeyboardConfigure.details.isSignleKey = 0;
    KeyboardConfigure.details.isSignleTouch = 0;
    SelectReportMode();
    KeyboardData.details.ReportKey[0] = 8;
    // 按键初始化
#if (PresskeyGroup == 'A')
    GPIOA_ModeCfg(Presskey, GPIO_ModeIN_PU); // 下拉输入，此时的引脚电平为低电平
    GPIOA_SetBits(Presskey);
    GPIOA_ITModeCfg(Presskey, GPIO_ITMode_FallEdge); // 配置上升沿触发中断
#elif (PresskeyGroup == 'B')
    GPIOB_ModeCfg(Presskey, GPIO_ModeIN_PU); // 按键初始化
    GPIOB_SetBits(Presskey);
    GPIOB_ITModeCfg(Presskey, GPIO_ITMode_FallEdge); // 配置上升沿触发中断
#endif
    // EEPROM_READ(0, KeyboardConfigure.data, KeyboardConfigureSize);
}
/**
 * @brief           选择按键工作模式
 *  @details        【不能简单描述则必选】如果不能一句话描述函数，请使用Details进行详细描述
 *
 *
 * */
/*
 * 创建者:             Winyunq
 * 创建日期:            2022-12-25
 *
 *      《初始化》
 * 修订内容:            创建函数
 * @author          Winyunq进行完善
 * @date            2022-12-25
 * @version         1.0.0
 */
void SelectReportMode()
{
    // ReportKeyValue=UTF8KeyReport;

    KeyboardData.buffer[0] = 4; // alt
    KeyboardData.buffer[1] = 0; //
    KeyboardData.buffer[3] = 0; //
    KeyboardData.buffer[4] = 0; //
    KeyboardData.buffer[5] = 0; //
    KeyboardData.buffer[6] = 0; //
    KeyboardData.buffer[7] = 0; //
    ReportKeyValue = UTF8KeyReport;
}
/**
 * @brief           按键事件
 *  @details        按键事件函数，将以每
 *
 *
 * */
/*
 * 创建者:             Winyunq
 * 创建日期:            2022-12-18
 *
 *      《初始化》
 * 修订内容:            创建函数
 * @author          Winyunq进行完善
 * @date            2022-12-18
 * @version         1.0.0
 */
void KeyboardEvent()
{
    /// 将Report的内容分散到多次KeyboardEvent，保证每个按键均有作用时间
    if (NowReportTime)
    {
        NowReportTime++;
        ReportKeyValue();
    }
    if ((!NowReportTime) && IsTouch())
    {
        printf("\n keyboard");
        NowReportTime = 1;
        ReportKeyValue();
        WaitNewKey();
        /*
        switch(0b10){
            case 0b01:
            case 0b10:StringReport();
        }*/
        /*if(!KeyboardConfigure.details.isSignleTouch){
            WaitNewKey();
        }*/
    }
}
/**
 * @brief           按键模式
 *  @details        同时支持连点器模式和单点模式
 * | 模式 | 效果 |
 * | ---- | ---- |
 * | 连点-单点 | 单个按键，0:按下按键连续发送ReportType对应的按键及其状态键；1:按键按下后等于ReportKey所对应的按键  |
 * | 连点模式 | 当按下按键后会立刻上报松开。若按键一直按下，将会以按下-松开-按下-松开工作，形成连点 |
 * | 单点模式 | 仅按键按下时上报按键按下。直到按键松开之前，不会上报按键松开。若按键一直按下，表现为按住不放 |
 *
 *
 * */
/*
 * 创建者:             Winyunq
 * 创建日期:            2022-12-16
 *
 *      《初始化》
 * 修订内容:            创建函数
 * @author          Winyunq进行完善
 * @date            2022-12-16
 * @version         1.0.0
 */
void SignleKeyReport()
{
    /// 这是一个优化技巧：当且仅当按键刚刚按下时，NowReportTime=1，此时上报按键改变状态。而之后NowReportTime将=2，将跳过发送蓝牙数据包。
    /// 当没有蓝牙数据包时键盘将保持当前状态，如此将减少大量无效数据包的发送降低功耗

    if (NowReportTime == 1)
        HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, 8, KeyboardData.buffer);
    /// 若为连点模式，当按键按下后可以立刻松开按键，即NowReportTime=0且发送松开按键
    /// 若为单点模式，只有在按键松开，即对应IO为高电平时，才发送松开按键
    if (!KeyboardConfigure.details.isSignleTouch || isReleaseKey())
    {
        NowReportTime = 0;

        HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, 8, ReleaseKeyTouch);
    }
    NowReportTime = 1;
}
/**
 * @brief           动作键模式
 *  @details        每次按下按键将执行下一个按键
 *
 *
 * */
/*
 * 创建者:             Winyunq
 * 创建日期:            2022-12-17
 *
 *      《初始化》
 * 修订内容:            创建函数
 * @author          Winyunq进行完善
 * @date            2022-12-17
 * @version         1.0.0
 */
void ActionKeyReport()
{
}
/**
 * @brief           字符串按键
 *  @details        根据字符串信息，依次按下按键，最多支持18个字节的长度
 *
 *
 * */
/*
 * 创建者:             Winyunq
 * 创建日期:            2022-12-16
 *
 *      《初始化》
 * 修订内容:            创建函数
 * @author          Winyunq进行完善
 * @date            2022-12-16
 * @version         1.0.0
 */
void StringReport()
{
    KeyboardData.details.ReportKey[0] = KeyboardConfigure.data[NowReportTime] - 'A' + 4;
    printf("\n report");
    printf(KeyboardConfigure.data[NowReportTime]);
    HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, 8, KeyboardData.buffer);
    if ((!KeyboardConfigure.data[NowReportTime]))
    {
        NowReportTime = 0;
    }
}
#define GetNumber(number) (number + 88)
/**
 * @brief           函数简介
 *  @details        【不能简单描述则必选】如果不能一句话描述函数，请使用Details进行详细描述
 *
 *
 * */
/*
 * 创建者:             Winyunq
 * 创建日期:            2022-12-25
 *
 *      《初始化》
 * 修订内容:            创建函数
 * @author          Winyunq进行完善
 * @date            2022-12-25
 * @version         1.0.0
 */
void UTF8StringReport()
{
    /// 解析现在要发送的键盘数据包
    switch (ReportChar[NowReportTime])
    {
    /// 表示全部数据已经发送完毕
    case 0:
        /// 关闭键盘上报状态
        NowReportTime = 0;
        break;
    /// 表示进入下一个按键输入，需要发送一次全部松开，进入第二个输入状态
    case ' ':
        HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, 8, ReleaseKeyTouch);
        break;
    /// 直接枚举数据也行。
    default:
        KeyboardData.data = 0;      //
        KeyboardData.buffer[0] = 4; // 按下alt，且alt不松开
        KeyboardData.buffer[1] = 0; //
        KeyboardData.buffer[2] = 0; // 按下alt，且alt不松开
        KeyboardData.buffer[3] = 0; //
        KeyboardData.buffer[4] = 0; // 按下alt，且alt不松开
        KeyboardData.buffer[5] = 0; //
        KeyboardData.buffer[6] = 0; // 按下alt，且alt不松开
        KeyboardData.buffer[7] = 0; //        KeyboardData.buffer[0] = 4; // 按下alt，且alt不松开

        for (int index = 2; index < 8; index++)
        {
            /// 当ReportChar[NowReportTime]=' '(空格)，表示接下来的数据是下一个字，因此需要NowReportTime--;使得指针指向上一次的数据，以便下次EVENT的时候指向空格
            if (ReportChar[NowReportTime] == ' ')
            {
                NowReportTime--;
                break;
            }
            /// @brief 0并不是在9后面，需要特殊处理
            if (ReportChar[NowReportTime] == '0')
            {
                KeyboardData.buffer[index] = 0x27;
            }
            else
            {
                KeyboardData.buffer[index] = ReportChar[NowReportTime] - '1' + 0x1E;
            }
            NowReportTime++;
        }
        HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, 8, KeyboardData.buffer);
    }
}
void UTF8KeyReport()
{
    /// 这是一个优化技巧：当且仅当按键刚刚按下时，NowReportTime=1，此时上报按键改变状态。而之后NowReportTime将=2，将跳过发送蓝牙数据包。
    /// 当没有蓝牙数据包时键盘将保持当前状态，如此将减少大量无效数据包的发送降低功耗
    if (NowReportTime == 1)
    {
        KeyboardData.buffer[0] = 4;            // 按下alt，且alt不松开
        KeyboardData.buffer[1] = 0;            //
        KeyboardData.buffer[2] = GetNumber(4); // 按下小数字键盘的4
        KeyboardData.buffer[3] = GetNumber(8); // 按下小数字键盘的8
        KeyboardData.buffer[4] = GetNumber(1); // 按下小数字键盘的1
        KeyboardData.buffer[5] = GetNumber(2); // 按下小数字键盘的2
        KeyboardData.buffer[6] = GetNumber(5); // 按下小数字键盘的5
        HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, 8, KeyboardData.buffer);
    }
    /// 若为连点模式，当按键按下后可以立刻松开按键，即NowReportTime=0且发送松开按键
    /// 若为单点模式，只有在按键松开，即对应IO为高电平时，才发送松开按键
    if (!KeyboardConfigure.details.isSignleTouch || isReleaseKey())
    {
        NowReportTime = 0;

        HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, 8, ReleaseKeyTouch);

        // 全部键抬起来，包括alt，0，1,2,3,
    }
    // NowReportTime = 1;
    // 有NowReportTime = 1这句会导致发送一次后，无法再发送第二次
}